import { Cube3D } from '@/assets/basesrc/cube3d';
import { RubiksCube } from '@/assets/basesrc/rubikscube';
import { CubeAttributes } from '@/assets/basesrc/cubeattributes';
import { Node3D } from '@/assets/basesrc/node3d';
import { J3DIMatrix4 } from '@/assets/basesrc/J3DIMath';
import { SplineInterpolator } from '@/assets/basesrc/splineinterpolator';


/** Constructor
 * Creates the geometry of a Rubik's Cube.
 */
var RubiksCube3D = function () {
  this.RubiksCube3DInit();
}

RubiksCube3D.prototype = new Cube3D();

Cube3D.prototype.cornerCount = 8;
Cube3D.prototype.edgeCount = 12;
Cube3D.prototype.sideCount = 6;
Cube3D.prototype.centerCount = 1;
Cube3D.prototype.partCount = 8 + 12 + 6 + 1;
Cube3D.prototype.cornerOffset = 0;
Cube3D.prototype.edgeOffset = 8;
Cube3D.prototype.sideOffset = 8 + 12;
Cube3D.prototype.centerOffset = 8 + 12 + 6;

RubiksCube3D.prototype.RubiksCube3DInit = function () {
  if (true) {
    this.alphak = 0;
    this.cornerCount = 8;
    this.edgeCount = 12;
    this.sideCount = 6;
    this.centerCount = 1;
    this.partCount = 8 + 12 + 6 + 1;
    this.cornerOffset = 0;
    this.edgeOffset = 8;
    this.sideOffset = 8 + 12;
    this.centerOffset = 8 + 12 + 6;
    this.stickerCount = 9 * 6;

    this.Cube3DInit(); // initialize super class
    this.cube = new RubiksCube();
    this.cube.addCubeListener(this);
    this.attributes = this.createAttributes();

    this.partToStickerMap = new Array(this.partCount);
    for (var i = 0; i < this.partCount; i++) {
      this.parts[i] = new Node3D();
      this.rotationTransforms[i] = new Node3D();
      this.explosionTransforms[i] = new Node3D();
      this.locationTransforms[i] = new Node3D();

      this.explosionTransforms[i].add(this.parts[i]);
      this.locationTransforms[i].add(this.explosionTransforms[i]);
      this.rotationTransforms[i].add(this.locationTransforms[i]);
      this.add(this.rotationTransforms[i]);

      this.identityVertexMatrix[i] = new J3DIMatrix4();

      this.partToStickerMap[i] = new Array(3);
    }

    for (var i = 0; i < this.stickerCount; i++) {
      this.partToStickerMap[this.stickerToPartMap[i]][this.stickerToFaceMap[i]] = i;
    }

    var partSize = this.cube.partSize;
    var cornerScale = this.cube.cornerScale;
    var cornetTranslate = this.cube.cornetTranslate;


    /*
     * Corners
     */
    var cornerOffset = this.cornerOffset;
    // Move all corner parts to up front left (ufl) and then rotate them in place
    for (var i = 0; i < this.cornerCount; i++) {
      var index = cornerOffset + i;
      this.explosionTransforms[index].matrix.translate(-partSize, partSize, -partSize);
      this.explosionTransforms[index].matrix.rotate(180, 0, 1, 0);
    }

    // 0:urf
    this.identityVertexMatrix[cornerOffset + 0].rotate(90, 0, -1, 0);
    this.identityVertexMatrix[cornerOffset + 0].scale(...cornerScale[0]);
    this.identityVertexMatrix[cornerOffset + 0].translate(...cornetTranslate[0]);
    console.log(this.identityVertexMatrix[cornerOffset].$matrix)
    // 1:dfr
    this.identityVertexMatrix[cornerOffset + 1].rotate(180, 0, 0, 1);
    this.identityVertexMatrix[cornerOffset + 1].scale(...cornerScale[1]);
    this.identityVertexMatrix[cornerOffset + 1].translate(...cornetTranslate[1]);
    // 2:ubr
    this.identityVertexMatrix[cornerOffset + 2].rotate(180, 0, 1, 0);
    this.identityVertexMatrix[cornerOffset + 2].scale(...cornerScale[2]);
    this.identityVertexMatrix[cornerOffset + 2].translate(...cornetTranslate[2]);
    // 3:drb
    this.identityVertexMatrix[cornerOffset + 3].rotate(90, 0, -1, 0);
    this.identityVertexMatrix[cornerOffset + 3].rotate(180, 0, 0, 1);
    this.identityVertexMatrix[cornerOffset + 3].scale(...cornerScale[3]);
    this.identityVertexMatrix[cornerOffset + 3].translate(...cornetTranslate[3]);
    // 4:ulb
    this.identityVertexMatrix[cornerOffset + 4].rotate(90, 0, 1, 0);
    this.identityVertexMatrix[cornerOffset + 4].scale(...cornerScale[4]);
    this.identityVertexMatrix[cornerOffset + 4].translate(...cornetTranslate[4]);
    // 5:dbl
    this.identityVertexMatrix[cornerOffset + 5].rotate(180, 1, 0, 0);
    this.identityVertexMatrix[cornerOffset + 5].scale(...cornerScale[5]);
    this.identityVertexMatrix[cornerOffset + 5].translate(...cornetTranslate[5]);
    // 6:ufl
    this.identityVertexMatrix[cornerOffset + 6].scale(...cornerScale[6]);
    this.identityVertexMatrix[cornerOffset + 6].translate(...cornetTranslate[6]);
    // 7:dlf
    this.identityVertexMatrix[cornerOffset + 7].rotate(180, 1, 0, 0);
    this.identityVertexMatrix[cornerOffset + 7].rotate(90, 0, 1, 0);
    this.identityVertexMatrix[cornerOffset + 7].scale(...cornerScale[7]);
    this.identityVertexMatrix[cornerOffset + 7].translate(...cornetTranslate[7]);
    //
    /**
     * Edges
     */
    // Move all edge parts to front up (fu) and then rotate them in place
    var edgeOffset = this.edgeOffset;
    for (var i = 0; i < this.edgeCount; i++) {
      var index = edgeOffset + i;
      this.explosionTransforms[index].matrix.translate(0, partSize, -partSize);
      this.explosionTransforms[index].matrix.rotate(180, 0, 1, 0);
    }
    // ur
    this.identityVertexMatrix[edgeOffset + 0].rotate(90, 0, 0, -1);
    this.identityVertexMatrix[edgeOffset + 0].rotate(90, 0, 1, 0);
    this.identityVertexMatrix[edgeOffset + 0].scale(1, 1.2, 0.8);
    this.identityVertexMatrix[edgeOffset + 0].translate(0, -partSize * 0.05, -partSize * 0.15);
    // rf
    this.identityVertexMatrix[edgeOffset + 1].rotate(90, -1, 0, 0);
    this.identityVertexMatrix[edgeOffset + 1].rotate(90, 0, -1, 0);
    this.identityVertexMatrix[edgeOffset + 1].scale(1, 0.8, 1.2);
    this.identityVertexMatrix[edgeOffset + 1].translate(0, partSize * 0.15, partSize * 0.05);
    // dr
    this.identityVertexMatrix[edgeOffset + 2].rotate(90, 0, 0, -1);
    this.identityVertexMatrix[edgeOffset + 2].rotate(90, 0, -1, 0);
    this.identityVertexMatrix[edgeOffset + 2].scale(1, 1.2, 1.2);
    this.identityVertexMatrix[edgeOffset + 2].translate(0, -partSize * 0.05, partSize * 0.05);
    // bu
    this.identityVertexMatrix[edgeOffset + 3].rotate(180, 0, 1, 0);
    this.identityVertexMatrix[edgeOffset + 3].scale(1, 0.8, 1.2);
    this.identityVertexMatrix[edgeOffset + 3].translate(0, partSize * 0.15, partSize * 0.05);
    // rb
    this.identityVertexMatrix[edgeOffset + 4].rotate(90, 0, -1, 0);
    this.identityVertexMatrix[edgeOffset + 4].rotate(90, 0, 0, -1);
    this.identityVertexMatrix[edgeOffset + 4].scale(1, 1.2, 1.2);
    this.identityVertexMatrix[edgeOffset + 4].translate(0, -partSize * 0.05, partSize * 0.05);
    // bd
    this.identityVertexMatrix[edgeOffset + 5].rotate(180, 1, 0, 0);
    this.identityVertexMatrix[edgeOffset + 5].scale(1, 1.2, 1.2);
    this.identityVertexMatrix[edgeOffset + 5].translate(0, -partSize * 0.05, partSize * 0.05);
    // ul
    this.identityVertexMatrix[edgeOffset + 6].rotate(90, 0, -1, 0);
    this.identityVertexMatrix[edgeOffset + 6].rotate(90, 1, 0, 0);
    this.identityVertexMatrix[edgeOffset + 6].scale(1, 0.8, 0.8);
    this.identityVertexMatrix[edgeOffset + 6].translate(0, partSize * 0.15, -partSize * 0.15);
    // lb
    this.identityVertexMatrix[edgeOffset + 7].rotate(90, 0, 1, 0);
    this.identityVertexMatrix[edgeOffset + 7].rotate(90, 0, 0, 1);
    this.identityVertexMatrix[edgeOffset + 7].scale(1, 1.2, 0.8);
    this.identityVertexMatrix[edgeOffset + 7].translate(0, -partSize * 0.05, -partSize * 0.15);
    // dl
    this.identityVertexMatrix[edgeOffset + 8].rotate(90, 0, 1, 0);
    this.identityVertexMatrix[edgeOffset + 8].rotate(90, -1, 0, 0);
    this.identityVertexMatrix[edgeOffset + 8].scale(1, 0.8, 1.2);
    this.identityVertexMatrix[edgeOffset + 8].translate(0, partSize * 0.15, partSize * 0.05);
    // fu
    this.identityVertexMatrix[edgeOffset + 9].scale(1, 0.8, 0.8);
    this.identityVertexMatrix[edgeOffset + 9].translate(0, partSize * 0.15, -partSize * 0.15);
    // lf
    this.identityVertexMatrix[edgeOffset + 10].rotate(90, 0, 1, 0);
    this.identityVertexMatrix[edgeOffset + 10].rotate(90, 0, 0, -1);
    this.identityVertexMatrix[edgeOffset + 10].scale(1, 0.8, 0.8);
    this.identityVertexMatrix[edgeOffset + 10].translate(0, partSize * 0.15, -partSize * 0.15);

    // fd
    this.identityVertexMatrix[edgeOffset + 11].rotate(180, 0, 0, 1);
    this.identityVertexMatrix[edgeOffset + 11].scale(1, 1.2, 0.8);
    this.identityVertexMatrix[edgeOffset + 11].translate(0, -partSize * 0.05, -partSize * 0.15);
    /* Sides
     */
    // Move all side parts to front
    var sideOffset = this.sideOffset;
    for (var i = 0; i < this.sideCount; i++) {
      var index = sideOffset + i;
      this.explosionTransforms[index].matrix.translate(0, 0, -partSize);
      this.explosionTransforms[index].matrix.rotate(180, 0, 1, 0);
    }

    // r
    this.identityVertexMatrix[sideOffset + 0].rotate(90, 0, -1, 0);
    this.identityVertexMatrix[sideOffset + 0].rotate(90, 0, 0, -1);
    this.identityVertexMatrix[sideOffset + 0].scale(1, 1, 1.2);
    this.identityVertexMatrix[sideOffset + 0].translate(0, 0, partSize * 0.05);
    // u
    this.identityVertexMatrix[sideOffset + 1].rotate(90, 1, 0, 0);
    this.identityVertexMatrix[sideOffset + 1].rotate(90, 0, 0, 1);
    this.identityVertexMatrix[sideOffset + 1].scale(1, 1, 0.8);
    this.identityVertexMatrix[sideOffset + 1].translate(0, 0, -partSize * 0.15);
    // f
    this.identityVertexMatrix[sideOffset + 2].scale(1, 1, 0.8);
    this.identityVertexMatrix[sideOffset + 2].translate(0, 0, -partSize * 0.15);
    // l
    this.identityVertexMatrix[sideOffset + 3].rotate(90, 0, 1, 0);
    this.identityVertexMatrix[sideOffset + 3].rotate(180, 0, 0, 1);
    this.identityVertexMatrix[sideOffset + 3].scale(1, 1, 0.8);
    this.identityVertexMatrix[sideOffset + 3].translate(0, 0, -partSize * 0.15);
    // d
    this.identityVertexMatrix[sideOffset + 4].rotate(180, 0, 0, 1);
    this.identityVertexMatrix[sideOffset + 4].rotate(90, 1, 0, 0);
    this.identityVertexMatrix[sideOffset + 4].scale(1, 1, 1.2);
    this.identityVertexMatrix[sideOffset + 4].translate(0, 0, partSize * 0.05);
    // b
    this.identityVertexMatrix[sideOffset + 5].rotate(90, 0, 0, 1);
    this.identityVertexMatrix[sideOffset + 5].rotate(180, 0, 1, 0);
    this.identityVertexMatrix[sideOffset + 5].scale(1, 1, 1.2);
    this.identityVertexMatrix[sideOffset + 5].translate(0, 0, partSize * 0.05);

    // ----------------------------         
    // Reset all rotations
    for (var i = 0; i < this.partCount; i++) {
      this.locationTransforms[i].matrix.load(this.identityVertexMatrix[i]);
    }
  }
}

/* Maps stickers to cube parts.
 */
RubiksCube3D.prototype.stickerToPartMap = [
  0, 8, 2, 9, 20, 12, 1, 10, 3, // right
  4, 11, 2, 14, 21, 8, 6, 17, 0, // up
  6, 17, 0, 18, 22, 9, 7, 19, 1, // front
  4, 14, 6, 15, 23, 18, 5, 16, 7, // left
  7, 19, 1, 16, 24, 10, 5, 13, 3, // down
  2, 11, 4, 12, 25, 15, 3, 13, 5 // back
];

/** Maps parts to stickers. This is a two dimensional array. The first
 * dimension is the part index, the second dimension the orientation of
 * the part. */
RubiksCube3D.prototype.partToStickerMap = null;
RubiksCube3D.prototype.getStickerIndexForPartIndex = function (partIndex, orientationIndex) {
  return this.partToStickerMap[partIndex][orientationIndex];
}

RubiksCube3D.prototype.getPartIndexForStickerIndex = function (stickerIndex) {
  return stickerToPartMap[stickerIndex];
}
RubiksCube3D.prototype.stickerToFaceMap = [
  1, 1, 2, 0, 0, 0, 2, 1, 1, // right
  0, 1, 0, 0, 0, 0, 0, 1, 0, // up
  1, 0, 2, 1, 0, 1, 2, 0, 1, // front
  1, 1, 2, 0, 0, 0, 2, 1, 1, // left
  0, 1, 0, 0, 0, 0, 0, 1, 0, // down
  1, 0, 2, 1, 0, 1, 2, 0, 1 // back
];

/** Default cube attributes. */
RubiksCube3D.prototype.createAttributes = function () {
  var a = new CubeAttributes(this.partCount, 6 * 9, [9, 9, 9, 9, 9, 9]);
  var partsPhong = [0.5, 0.6, 0.4, 16.0];//shiny plastic [ambient, diffuse, specular, shininess]
  for (var i = 0; i < this.partCount; i++) {
    a.partsFillColor[i] = [40, 40, 40, 255];
    a.partsPhong[i] = partsPhong;
  }
  a.partsFillColor[this.centerOffset] = [240, 240, 240, 255];

  var faceColors = [
    [255, 210, 0, 255],// right: yellow
    [0, 51, 115, 255],// up   : blue
    [140, 0, 15, 255],// front: red
    [248, 248, 248, 255],// left : white
    [0, 115, 47, 255],// down : green
    [255, 70, 0, 255] // back : orange
  ];

  var stickersPhong = [0.8, 0.2, 0.1, 8.0];//shiny paper [ambient, diffuse, specular, shininess]

  for (var i = 0; i < 6; i++) {
    for (var j = 0; j < 9; j++) {
      a.stickersFillColor[i * 9 + j] = faceColors[i];
      a.stickersPhong[i * 9 + j] = stickersPhong;
    }
  }

  return a;
}

RubiksCube3D.prototype.transform3d = function () {

  // // this.partToStickerMap = new Array(this.partCount);
  for (var i = 0; i < this.partCount; i++) {
    //   // this.parts[i] = new Node3D();
    //   // this.rotationTransforms[i] = new Node3D();
    //   // this.explosionTransforms[i] = new Node3D();
    //   // this.locationTransforms[i] = new Node3D();

    //   // this.explosionTransforms[i].add(this.parts[i]);
    //   // this.locationTransforms[i].add(this.explosionTransforms[i]);
    //   // this.rotationTransforms[i].add(this.locationTransforms[i]);
    //   // this.add(this.rotationTransforms[i]);

    this.identityVertexMatrix[i] = new J3DIMatrix4();

    //   // this.partToStickerMap[i] = new Array(3);
  }

  // for (var i = 0; i < this.stickerCount; i++) {
  //   this.partToStickerMap[this.stickerToPartMap[i]][this.stickerToFaceMap[i]] = i;
  // }

  var partSize = this.cube.partSize;
  var cornerScale = this.cube.cornerScale;
  var cornetTranslate = this.cube.cornetTranslate;
  var edgeScale = this.cube.edgeScale;
  var edgeTranslate = this.cube.edgeTranslate;
  var sideScale = this.cube.sideScale;
  var sideTranslate = this.cube.sideTranslate;

  /*
   * Corners
   */
  var cornerOffset = this.cornerOffset;
  // Move all corner parts to up front left (ufl) and then rotate them in place
  // for (var i = 0; i < this.cornerCount; i++) {
  //   var index = cornerOffset + i;
  //   this.explosionTransforms[index].matrix.translate(-partSize, partSize, -partSize);
  //   this.explosionTransforms[index].matrix.rotate(180, 0, 1, 0);
  // }

  // 0:urf
  this.identityVertexMatrix[cornerOffset + 0].rotate(90, 0, -1, 0);
  this.identityVertexMatrix[cornerOffset + 0].scale(...cornerScale[0]);
  this.identityVertexMatrix[cornerOffset + 0].translate(...cornetTranslate[0]);
  // 1:dfr
  this.identityVertexMatrix[cornerOffset + 1].rotate(180, 0, 0, 1);
  this.identityVertexMatrix[cornerOffset + 1].scale(...cornerScale[1]);
  this.identityVertexMatrix[cornerOffset + 1].translate(...cornetTranslate[1]);
  // 2:ubr
  this.identityVertexMatrix[cornerOffset + 2].rotate(180, 0, 1, 0);
  this.identityVertexMatrix[cornerOffset + 2].scale(...cornerScale[2]);
  this.identityVertexMatrix[cornerOffset + 2].translate(...cornetTranslate[2]);
  // 3:drb
  this.identityVertexMatrix[cornerOffset + 3].rotate(90, 0, -1, 0);
  this.identityVertexMatrix[cornerOffset + 3].rotate(180, 0, 0, 1);
  this.identityVertexMatrix[cornerOffset + 3].scale(...cornerScale[3]);
  this.identityVertexMatrix[cornerOffset + 3].translate(...cornetTranslate[3]);
  // 4:ulb
  this.identityVertexMatrix[cornerOffset + 4].rotate(90, 0, 1, 0);
  this.identityVertexMatrix[cornerOffset + 4].scale(...cornerScale[4]);
  this.identityVertexMatrix[cornerOffset + 4].translate(...cornetTranslate[4]);
  // 5:dbl
  this.identityVertexMatrix[cornerOffset + 5].rotate(180, 1, 0, 0);
  this.identityVertexMatrix[cornerOffset + 5].scale(...cornerScale[5]);
  this.identityVertexMatrix[cornerOffset + 5].translate(...cornetTranslate[5]);
  // 6:ufl
  this.identityVertexMatrix[cornerOffset + 6].scale(...cornerScale[6]);
  this.identityVertexMatrix[cornerOffset + 6].translate(...cornetTranslate[6]);
  // 7:dlf
  this.identityVertexMatrix[cornerOffset + 7].rotate(180, 1, 0, 0);
  this.identityVertexMatrix[cornerOffset + 7].rotate(90, 0, 1, 0);
  this.identityVertexMatrix[cornerOffset + 7].scale(...cornerScale[7]);
  this.identityVertexMatrix[cornerOffset + 7].translate(...cornetTranslate[7]);

  /**
   * Edges
   */
  // Move all edge parts to front up (fu) and then rotate them in place
  var edgeOffset = this.edgeOffset;
  // for (var i = 0; i < this.edgeCount; i++) {
  //   var index = edgeOffset + i;
  //   this.explosionTransforms[index].matrix.translate(0, partSize, -partSize);
  //   this.explosionTransforms[index].matrix.rotate(180, 0, 1, 0);
  // }
  // ur
  this.identityVertexMatrix[edgeOffset + 0].rotate(90, 0, 0, -1);
  this.identityVertexMatrix[edgeOffset + 0].rotate(90, 0, 1, 0);
  this.identityVertexMatrix[edgeOffset + 0].scale(...edgeScale[0]);
  this.identityVertexMatrix[edgeOffset + 0].translate(...edgeTranslate[0]);
  // rf
  this.identityVertexMatrix[edgeOffset + 1].rotate(90, -1, 0, 0);
  this.identityVertexMatrix[edgeOffset + 1].rotate(90, 0, -1, 0);
  this.identityVertexMatrix[edgeOffset + 1].scale(...edgeScale[1]);
  this.identityVertexMatrix[edgeOffset + 1].translate(...edgeTranslate[1]);
  // dr
  this.identityVertexMatrix[edgeOffset + 2].rotate(90, 0, 0, -1);
  this.identityVertexMatrix[edgeOffset + 2].rotate(90, 0, -1, 0);
  this.identityVertexMatrix[edgeOffset + 2].scale(...edgeScale[2]);
  this.identityVertexMatrix[edgeOffset + 2].translate(...edgeTranslate[2]);
  // bu
  this.identityVertexMatrix[edgeOffset + 3].rotate(180, 0, 1, 0);
  this.identityVertexMatrix[edgeOffset + 3].scale(...edgeScale[3]);
  this.identityVertexMatrix[edgeOffset + 3].translate(...edgeTranslate[3]);
  // rb
  this.identityVertexMatrix[edgeOffset + 4].rotate(90, 0, -1, 0);
  this.identityVertexMatrix[edgeOffset + 4].rotate(90, 0, 0, -1);
  this.identityVertexMatrix[edgeOffset + 4].scale(...edgeScale[4]);
  this.identityVertexMatrix[edgeOffset + 4].translate(...edgeTranslate[4]);
  // bd
  this.identityVertexMatrix[edgeOffset + 5].rotate(180, 1, 0, 0);
  this.identityVertexMatrix[edgeOffset + 5].scale(...edgeScale[5]);
  this.identityVertexMatrix[edgeOffset + 5].translate(...edgeTranslate[5]);
  // ul
  this.identityVertexMatrix[edgeOffset + 6].rotate(90, 0, -1, 0);
  this.identityVertexMatrix[edgeOffset + 6].rotate(90, 1, 0, 0);
  this.identityVertexMatrix[edgeOffset + 6].scale(...edgeScale[6]);
  this.identityVertexMatrix[edgeOffset + 6].translate(...edgeTranslate[6]);
  // lb
  this.identityVertexMatrix[edgeOffset + 7].rotate(90, 0, 1, 0);
  this.identityVertexMatrix[edgeOffset + 7].rotate(90, 0, 0, 1);
  this.identityVertexMatrix[edgeOffset + 7].scale(...edgeScale[7]);
  this.identityVertexMatrix[edgeOffset + 7].translate(...edgeTranslate[7]);
  // dl
  this.identityVertexMatrix[edgeOffset + 8].rotate(90, 0, 1, 0);
  this.identityVertexMatrix[edgeOffset + 8].rotate(90, -1, 0, 0);
  this.identityVertexMatrix[edgeOffset + 8].scale(...edgeScale[8]);
  this.identityVertexMatrix[edgeOffset + 8].translate(...edgeTranslate[8]);
  // fu
  this.identityVertexMatrix[edgeOffset + 9].scale(...edgeScale[9]);
  this.identityVertexMatrix[edgeOffset + 9].translate(...edgeTranslate[9]);
  // lf
  this.identityVertexMatrix[edgeOffset + 10].rotate(90, 0, 1, 0);
  this.identityVertexMatrix[edgeOffset + 10].rotate(90, 0, 0, -1);
  this.identityVertexMatrix[edgeOffset + 10].scale(...edgeScale[10]);
  this.identityVertexMatrix[edgeOffset + 10].translate(...edgeTranslate[10]);

  // fd
  this.identityVertexMatrix[edgeOffset + 11].rotate(180, 0, 0, 1);
  this.identityVertexMatrix[edgeOffset + 11].scale(...edgeScale[11]);
  this.identityVertexMatrix[edgeOffset + 11].translate(...edgeTranslate[11]);
  /* Sides
   */
  // Move all side parts to front
  var sideOffset = this.sideOffset;
  // for (var i = 0; i < this.sideCount; i++) {
  //   var index = sideOffset + i;
  //   this.explosionTransforms[index].matrix.translate(0, 0, -partSize);
  //   this.explosionTransforms[index].matrix.rotate(180, 0, 1, 0);
  // }

  // r
  this.identityVertexMatrix[sideOffset + 0].rotate(90, 0, -1, 0);
  this.identityVertexMatrix[sideOffset + 0].rotate(90, 0, 0, -1);
  this.identityVertexMatrix[sideOffset + 0].scale(1, 1, 1.2);
  this.identityVertexMatrix[sideOffset + 0].translate(0, 0, partSize * 0.05);
  // u
  this.identityVertexMatrix[sideOffset + 1].rotate(90, 1, 0, 0);
  this.identityVertexMatrix[sideOffset + 1].rotate(90, 0, 0, 1);
  this.identityVertexMatrix[sideOffset + 1].scale(1, 1, 0.8);
  this.identityVertexMatrix[sideOffset + 1].translate(0, 0, -partSize * 0.15);
  // f
  this.identityVertexMatrix[sideOffset + 2].scale(1, 1, 0.8);
  this.identityVertexMatrix[sideOffset + 2].translate(0, 0, -partSize * 0.15);
  // l
  this.identityVertexMatrix[sideOffset + 3].rotate(90, 0, 1, 0);
  this.identityVertexMatrix[sideOffset + 3].rotate(180, 0, 0, 1);
  this.identityVertexMatrix[sideOffset + 3].scale(1, 1, 0.8);
  this.identityVertexMatrix[sideOffset + 3].translate(0, 0, -partSize * 0.15);
  // d
  this.identityVertexMatrix[sideOffset + 4].rotate(180, 0, 0, 1);
  this.identityVertexMatrix[sideOffset + 4].rotate(90, 1, 0, 0);
  this.identityVertexMatrix[sideOffset + 4].scale(1, 1, 1.2);
  this.identityVertexMatrix[sideOffset + 4].translate(0, 0, partSize * 0.05);
  // b
  this.identityVertexMatrix[sideOffset + 5].rotate(90, 0, 0, 1);
  this.identityVertexMatrix[sideOffset + 5].rotate(180, 0, 1, 0);
  this.identityVertexMatrix[sideOffset + 5].scale(1, 1, 1.2);
  this.identityVertexMatrix[sideOffset + 5].translate(0, 0, partSize * 0.05);


  // ----------------------------         
  // Reset all rotations
  for (var i = 0; i < this.partCount; i++) {
    this.locationTransforms[i].matrix.load(this.identityVertexMatrix[i]);
  }
}

// 控制魔方形态转换（形状、颜色等）
RubiksCube3D.prototype.validateTwist = function (partIndices, locations, orientations, length,
  irrPartIndices, irrLocations, irrOrientations, irrLength, axis, angle, alpha) {
  var rotation = this.updateTwistRotation;
  rotation.makeIdentity();

  var rad = (90 * angle * (-alpha));
  switch (axis) {
    case 0:
      rotation.rotate(rad, -1, 0, 0);
      break;
    case 1:
      rotation.rotate(rad, 0, -1, 0);
      break;
    case 2:
      rotation.rotate(rad, 0, 0, 1);
      break;
  }

  // for (var j = 0; j < irrLength; j++) {
  //   this.locationTransforms[irrPartIndices[j]].matrix.load(this.identityVertexMatrix[irrLocations[j]]);
  // }

  var orientationMatrix = this.updateTwistOrientation;
  for (var i = 0; i < length; i++) {
    orientationMatrix.makeIdentity();
    if (partIndices[i] < this.edgeOffset) { //=> part is a corner
      switch (orientations[i]) {
        case 0:
          break;
        case 1:
          orientationMatrix.rotate(90, -1, 0, 0);
          orientationMatrix.rotate(90, 0, 0, -1);
          break;
        case 2:
          orientationMatrix.rotate(90, 0, 0, 1);
          orientationMatrix.rotate(90, 1, 0, 0);
          break;
      }
    } else if (partIndices[i] < this.sideOffset) { //=> part is an edge
      orientationMatrix.makeIdentity();
      if (orientations[i] == 1) {
        orientationMatrix.rotate(90, -1, 0, 0);
        orientationMatrix.rotate(180, 0, 0, 1);
      }
    } else if (partIndices[i] < this.centerOffset) {//=> part is a side
      if (orientations[i] > 0) {
        orientationMatrix.rotate(90 * orientations[i], 0, 0, 1);
      }
    }
    // this.parts[partIndices[i]].matrix.load(orientationMatrix);
    var transform = this.locationTransforms[locations[i]].matrix;

    transform.load(rotation);
    transform.multiply(this.identityVertexMatrix[locations[i]]);
    if (alpha == 1) {
      this.identityVertexMatrix[locations[i]].load(transform);
    }
  }
}

RubiksCube3D.prototype.cubeTwisted = function (evt) {
  if (this.repainter == null) {
    this.updateCube();
    return;
  }

  var layerMask = evt.layerMask;
  var axis = evt.axis;
  var angle = evt.angle;
  var model = this.cube;

  var partIndices = new Array(27);
  var locations = new Array(27);
  var orientations = new Array(27);
  var count = 0;
  var irrPartIndices = new Array(27);
  var irrLocations = new Array(27);
  var irrOrientations = new Array(27);
  var irrCount = 27 - count;
  for (var i = 0; i < 27; i++)irrLocations[i] = i;

  var affectedParts = evt.getAffectedLocations();
  if ((layerMask & 2) != 0) {
    count = affectedParts.length + 1;
    locations = affectedParts.slice(0, count);
    locations[count - 1] = this.centerOffset;
  } else {
    count = affectedParts.length;
    locations = affectedParts.slice(0, count);
  }
  // 获取旋转的块
  for (var i = 0; i < count; i++) {
    partIndices[i] = model.getPartAt(locations[i]);
    orientations[i] = model.getPartOrientation(partIndices[i]);
    irrLocations.splice(locations[i], 1);
  }
  // 其余块
  for (var i = 0; i < irrCount; i++) {
    irrPartIndices[i] = model.getPartAt(irrLocations[i]);
    irrOrientations[i] = model.getPartOrientation(irrLocations[i]);
  }

  // console.log(partIndices,orientations,locations);
  // console.log(irrPartIndices,irrOrientations,irrLocations);

  var finalCount = count;
  var self = this;
  var interpolator = new SplineInterpolator(0.25, 0, 0.75, 1);
  var start = new Date().getTime();
  var duration = this.attributes.twistDuration * Math.abs(angle);
  this.isTwisting = true;
  // this.alphak = (this.alphak + 1) % 4;
  var f = function () {
    var now = new Date().getTime();
    var elapsed = now - start;
    var value = elapsed / duration;
    if (value < 1) {
      self.validateTwist(partIndices, locations, orientations, finalCount,
        irrPartIndices, irrLocations, irrOrientations, irrCount,
        axis, angle, interpolator.getFraction(value) + self.alphak);
      self.repainter.repaint(f);
    } else {
      self.validateTwist(partIndices, locations, orientations, finalCount,
        irrPartIndices, irrLocations, irrOrientations, irrCount,
        axis, angle, 1.0 + self.alphak);
      self.isTwisting = false;
    }
  };
  this.repainter.repaint(f);
}

Cube3D.prototype.boxClickToAxisMap = [
  [[0, 1, 0], [2, 0, 2], [0, 1, 0]],// right
  [[1, 2, 1], [0, 1, 0], [1, 2, 1]],// down
  [[2, 1, 2], [0, 2, 0], [2, 1, 2]],// front
  [[0, 1, 0], [2, 0, 2], [0, 1, 0]],// left
  [[1, 2, 1], [0, 1, 0], [1, 2, 1]],// up
  [[2, 1, 2], [0, 2, 0], [2, 1, 2]],// back
];
Cube3D.prototype.boxClickToAngleMap = [
  [[-1, -1, -1], [-1, -1, 1], [-1, 1, -1]],
  [[-1, 1, -1], [1, -1, -1], [-1, -1, -1]],
  [[1, 1, 1], [-1, 1, 1], [1, -1, 1]],
  [[1, 1, 1], [1, 1, -1], [1, -1, 1]],
  [[1, -1, 1], [-1, 1, 1], [1, 1, 1]],
  [[-1, -1, -1], [1, -1, -1], [-1, 1, -1]],
];
Cube3D.prototype.boxClickToLayerMap = [
  [[1, 2, 1], [2, 1, 2], [1, 2, 1]],
  [[1, 2, 1], [2, 1, 2], [1, 2, 1]],
  [[4, 2, 4], [2, 4, 2], [4, 2, 4]],
  [[4, 2, 4], [2, 4, 2], [4, 2, 4]],
  [[4, 2, 4], [2, 4, 2], [4, 2, 4]],
  [[1, 2, 1], [2, 1, 2], [1, 2, 1]],
];
Cube3D.prototype.boxSwipeToAxisMap = [
  [1, 2, 1, 2],// left
  [2, 0, 2, 0],// down
  [1, 0, 1, 0],// front
  [1, 2, 1, 2],// right
  [2, 0, 2, 0],// up
  [1, 0, 1, 0],// back
];
Cube3D.prototype.boxSwipeToAngleMap = [
  [-1, -1, 1, 1],// left
  [1, 1, -1, -1],// down
  [1, -1, -1, 1],// front
  [1, 1, -1, -1],// right
  [-1, -1, 1, 1],// up
  [-1, 1, 1, -1],// back
];
Cube3D.prototype.boxSwipeToLayerMap = [
  [[[1, 4, 1, 4], [2, 4, 2, 4], [4, 4, 4, 4]], [[1, 2, 1, 2], [2, 2, 2, 2], [4, 2, 4, 2]], [[1, 1, 1, 1], [2, 1, 2, 1], [4, 1, 4, 1]]],// left
  [[[4, 1, 4, 1], [2, 1, 2, 1], [1, 1, 1, 1]], [[4, 2, 4, 2], [2, 2, 2, 2], [1, 2, 1, 2]], [[4, 4, 4, 4], [2, 4, 2, 4], [1, 4, 1, 4]]],// down
  [[[1, 1, 1, 1], [2, 1, 2, 1], [4, 1, 4, 1]], [[1, 2, 1, 2], [2, 2, 2, 2], [4, 2, 4, 2]], [[1, 4, 1, 4], [2, 4, 2, 4], [4, 4, 4, 4]]],// front
  [[[1, 4, 1, 4], [2, 4, 2, 4], [4, 4, 4, 4]], [[1, 2, 1, 2], [2, 2, 2, 2], [4, 2, 4, 2]], [[1, 1, 1, 1], [2, 1, 2, 1], [4, 1, 4, 1]]],// right
  [[[4, 1, 4, 1], [2, 1, 2, 1], [1, 1, 1, 1]], [[4, 2, 4, 2], [2, 2, 2, 2], [1, 2, 1, 2]], [[4, 4, 4, 4], [2, 4, 2, 4], [1, 4, 1, 4]]],// up
  [[[1, 1, 1, 1], [2, 1, 2, 1], [4, 1, 4, 1]], [[1, 2, 1, 2], [2, 2, 2, 2], [4, 2, 4, 2]], [[1, 4, 1, 4], [2, 4, 2, 4], [4, 4, 4, 4]]],// back
];

export { RubiksCube3D };